package ua.com.softway.db.batch;

import java.util.List;
import java.util.Random;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.xml.DOMConfigurator;
import org.hibernate.Criteria;

import ua.com.softway.db.Persistence;

/**
 * 200000 records, batch size 100
 * 
 * Limit/Offset impl: 
 *   Result: -1474736480
 *   Took 84 403ms
 *       
 * Id range impl:
 *   Result: -1474736480
*    Took  4 082ms
*    
*  Scrollable: TBD 
 */
public class StressTestBatchProcessor {
    @Entity
    @Table(name="uuser")
    public static class User {
        @Id @GeneratedValue(strategy=GenerationType.TABLE)
        public int id;
        public String name;
    }
    
    public static class UserJob implements BatchJob<User> {

        @Override
        public int getBatchSize() {
            return 100;
        }

        @Override
        public Criteria createCriteria() {
            return Persistence.createCriteria(User.class);
        }

        int result = 0;
        int current = 0;
        
        @Override
        public void processBatch(List<User> list) {
            for (User user : list) {
                result = result + user.id;
                
                if (current ++ % 10000 == 0)
                    System.out.println("Processed " + current);
                    
            }
        }

        long begin = System.currentTimeMillis();
        
        @Override
        public void completed() {
            System.out.println("Result: " + result);
            System.out.println("Took " + formatTime(System.currentTimeMillis() - begin));
        }

        private String formatTime(long ms) {
            return ms + "ms";
        }

        @Override
        public void failed() {
        }
        
    }
    
    public static void main(String[] args) throws InterruptedException {
        BasicConfigurator.resetConfiguration();
        DOMConfigurator.configure("log4j.xml");
     
        Persistence.configure("stresstest-hibernate.cfg.xml", User.class);
        Persistence.init();
        
        if (false) {
            generateRecords();
        } else {
            Thread t = new Thread(new BatchProcessor() { 
                @Override
                protected Batcher createBatcher(BatchJob<?> job) {
                    return new IdRangeBatcher(job.getBatchSize(), job.createCriteria());
                }
            });
            t.setDaemon(true);
            t.start();
            
            BatchProcessor.instance().addJob(new UserJob());
            BatchProcessor.instance().waitForCompletion();
        }
        
        Persistence.getEntityManagerFactory().close();
    }
    
    static void generateRecords() {
        BatchControl control = new BatchControl(5000);
        
        for (int i = 0; i < 200000; i ++) {
            control.begin();
            
            User user = new User();
            user.name = generateRandomString(10);
            
            Persistence.current().persist(user);
            
            control.commit();
            
            if (i % 10000 == 0)
                System.out.println(i);
            
        }
        
        control.forceCommit();
    }

    private static String generateRandomString(int size) {
        String password = "";

        Random r = new Random();

        String validChars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789";

        for (int i = 0; i < size; i++)
            password = password + validChars.charAt((r.nextInt((validChars.length()))));

        return password;
    }
}
